﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace Ha666.Redis
{

    /// <summary>
    /// String类型操作
    /// </summary>
    public abstract class RedisKey
    {
        /// <summary>
        /// 构造方法
        /// </summary>
        /// <param name="datakey">单个key</param>
        /// <param name="dtype">数据类型</param>
        public RedisKey(string datakey, DataType dtype)
        {
            DataKey = datakey;
            DataType = dtype;
            mIsSingleKey = true;
        }

        private bool mIsSingleKey = true;

        /// <summary>
        /// 构造方法
        /// </summary>
        /// <param name="datakey">key列表</param>
        /// <param name="dtype">数据类型</param>
        public RedisKey(IEnumerable<string> datakey, DataType dtype)
        {
            DataKey = datakey;
            DataType = dtype;
            mIsSingleKey = false;
        }

        protected object DataKey
        {
            get;
            set;
        }

        private string[] GetKeys
        {
            get
            {
                return ((IEnumerable<string>)DataKey).ToArray();
            }
        }

        /// <summary>
        /// 删除一个key
        /// </summary>
        /// <param name="serverid">服务器编号</param>
        public void Delete(int serverid)
        {
            RedisClient db = RedisClient.GetClient(null);
            if (mIsSingleKey)
                db.Delete(serverid, (string)DataKey);
            else
                db.Delete(GetKeys);
        }

        /// <summary>
        /// 设置一个key的过期时间
        /// </summary>
        /// <param name="serverid">服务器编号</param>
        /// <param name="time">过期时间，以秒为单位</param>
        public void Expire(int serverid, long time)
        {
            RedisClient db = RedisClient.GetClient(null);
            db.EXPIRE((string)DataKey, time, serverid);
        }

        /// <summary>
        /// 随机获取一个对象
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="serverid">服务器编号</param>
        /// <returns>对象</returns>
        public T RandKey<T>(int serverid)
        {
            RedisClient db = RedisClient.GetClient(null);
            return db.RANDOMKEY<T>(serverid);
        }

        /// <summary>
        /// 获取所有的key的列表。
        /// </summary>
        /// <param name="serverid">服务器编号</param>
        /// <returns>返回的是key的列表，注意：键名可以用通配符，比如说：* 匹配数据库中所有 key，具体信息请查看：http://www.redisdoc.com/en/latest/key/keys.html</returns>
        public IList<string> Keys(int serverid)
        {
            RedisClient db = RedisClient.GetClient(null);
            return db.Keys((string)DataKey, serverid);
        }

        /// <summary>
        /// 获取当前redis服务器的时间
        /// </summary>
        /// <param name="serverid">服务器编号</param>
        /// <returns>一个包含两个字符串的列表： 第一个字符串是当前时间(以 UNIX 时间戳格式表示)，而第二个字符串是当前这一秒钟已经逝去的微秒数。</returns>
        public List<string> Time(int serverid)
        {
            RedisClient db = RedisClient.GetClient(null);
            return db.Time(serverid);
        }

        protected DataType DataType
        {
            get;
            private set;
        }

        /// <summary>
        /// 获取一个对象
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="serverid">服务器编号</param>
        /// <returns>对象</returns>
        public T Get<T>(int serverid)
        {
            RedisClient db = RedisClient.GetClient(null);
            return db.Get<T>((string)DataKey, DataType, serverid);
        }

        /// <summary>
        /// 设置一个对象
        /// </summary>
        /// <param name="serverid">服务器编号</param>
        /// <param name="value">对象</param>
        public void Set(int serverid, object value)
        {
            RedisClient db = RedisClient.GetClient(null);
            db.Set((string)DataKey, value, DataType, serverid);
        }

        /// <summary>
        /// 将key中储存的数字值增一
        /// </summary>
        /// <param name="serverid">服务器编号</param>
        /// <returns>执行INCR命令之后key的值</returns>
        public int Incr(int serverid)
        {
            RedisClient db = RedisClient.GetClient(null);
            return db.Incr((string)DataKey, serverid);
        }

        /// <summary>
        /// 将key中储存的数字值减一
        /// </summary>
        /// <param name="serverid">服务器编号</param>
        /// <returns>执行DECR命令之后key的值</returns>
        public int Decr(int serverid)
        {
            RedisClient db = RedisClient.GetClient(null);
            return db.Decr((string)DataKey, serverid);
        }

        /// <summary>
        /// 同时设置一个或多个key-value对
        /// </summary>
        /// <param name="serverid">服务器编号</param>
        /// <param name="values">value数组</param>
        public void MSetValues(int serverid, object[] values)
        {
            RedisClient db = RedisClient.GetClient(null);
            List<Field> kvs = new List<Field>();
            string[] keys = GetKeys;
            int count = keys.Length > values.Length ? values.Length : keys.Length;
            for (int i = 0; i < count; i++)
                kvs.Add(new Field { Value = values[i], Name = keys[i] });
            db.MSet(kvs.ToArray(), DataType, serverid);
        }

        public IList<object> Get(int serverid, Type[] types)
        {
            RedisClient db = RedisClient.GetClient(null);
            return db.Get(types, GetKeys, DataType, serverid);
        }

        public IList<object> Get<T, T1>(int serverid)
        {
            RedisClient db = RedisClient.GetClient(null);
            return db.Get(new Type[] { typeof(T), typeof(T1) }, GetKeys, DataType, serverid);
        }

        public IList<object> Get<T, T1, T2>(int serverid)
        {
            RedisClient db = RedisClient.GetClient(null);
            return db.Get(new Type[] { typeof(T), typeof(T1), typeof(T2) }, GetKeys, DataType, serverid);
        }

        public IList<object> Get<T, T1, T2, T3>(int serverid)
        {
            RedisClient db = RedisClient.GetClient(null);
            return db.Get(new Type[] { typeof(T), typeof(T1), typeof(T2), typeof(T3) }, GetKeys, DataType, serverid);
        }

        public IList<object> Get<T, T1, T2, T3, T4>(int serverid)
        {
            RedisClient db = RedisClient.GetClient(null);
            return db.Get(new Type[] { typeof(T), typeof(T1), typeof(T2), typeof(T3), typeof(T4) }, GetKeys, DataType, serverid);
        }

    }

    /// <summary>
    /// 创建一个以key为名称的String类型的键(主要用于普通的string类型数据)
    /// </summary>
    public class StringKey : RedisKey
    {
        public StringKey(string key)
            : base(key, DataType.String)
        {
        }

        public StringKey(params string[] key)
            : base(key, DataType.String)
        {
        }
    }

    /// <summary>
    /// 创建一个以key为名称的String类型的键(主要用于经过Protobuf编码过的对象)
    /// </summary>
    public class ProtobufKey : RedisKey
    {
        public ProtobufKey(string key)
            : base(key, DataType.Protobuf)
        {
        }
        public ProtobufKey(params string[] key)
            : base(key, DataType.Protobuf)
        {
        }
    }

}
